/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package dameki.ki;

import dameki.game.GameMove;
import dameki.game.Stone;
import dameki.game.player.Player;
import dameki.output.ConsoleGUI;
import java.util.ArrayList;
import java.util.Random;

/**
 *
 * @author crazysaem
 */
public class Agent_crazysaem extends Player 
{
    public final static boolean COLOR_W = true;
    public final static boolean COLOR_B = false;
    
    public final static int STONE_KILLED = 4;
    public final static int STONE_MOVED = 0;
    public final static int STONE_SAVELY_MOVED = 1;
    public final static int STONE_UNSAVELY_MOVED = -4;
    public final static int STONE_SAVED = 2;
    
    private Random rand;
    private ConsoleGUI cgui;

    public Agent_crazysaem(boolean color) 
    {
        super(color);
        
        String cstring = "BLACK";
        if(color == COLOR_W)
            cstring = "WHITE";
        System.out.println("crazysaem is " + cstring);
        
        rand = new Random();
        cgui = new ConsoleGUI();
    }

    @Override
    public GameMove[] move(Stone[][] field) 
    {   
        //Create tree
        ScoreTree scoreTree = new ScoreTree();        
        scoreTree.isRoot = true;
        scoreTree.field = cloneFiled(field);
        
        scoreTree = generateScoreTree(scoreTree, this.color, 1, 4);
        
        generateMiniMaxValue(scoreTree);
        
        //System.out.println("---------DEBUG PRINT START-----------");
        //printScoreTreeFields(scoreTree, 0);
        //System.out.println("---------DEBUG PRINT END-------------");
                
        //Get max MinMax-Score        
        int minmaxValue = 9999999;
        for(int i=0; i<scoreTree.successor.size(); i++)
        {
            minmaxValue = Math.min(minmaxValue, scoreTree.successor.get(i).minmaxValue);
        }
        
        //Get the Set of trees with the same minmax-value:
        ArrayList<ScoreTree> scoreTreeList = new ArrayList();
        
        for(int i=0; i<scoreTree.successor.size(); i++)
        {
            if(scoreTree.successor.get(i).minmaxValue == minmaxValue)
            {
                scoreTreeList.add(scoreTree.successor.get(i));
            }
        }
        if(scoreTreeList.size()>0)
            return scoreTreeList.get(rand.nextInt(scoreTreeList.size())).gameMoves;
        else
            return null;
    }
    
    public void printScoreTreeFields(ScoreTree scoreTree, int depth)
    {           
        /*
        for(int i=0; i<scoreTree.successor.size(); i++)
        {
            System.out.println("Depth: " + depth + " pos: " + i);
            System.out.println("Score: " + scoreTree.successor.get(i).fieldScore + " Minimax: " + scoreTree.successor.get(i).minmaxValue);
            String cstring = "BLACK";
            if(scoreTree.successor.get(i).gameMoves[0].getStone().getColor() == COLOR_W)
                cstring = "WHITE";
            System.out.println("Color: " + cstring);
            cgui.update(scoreTree.successor.get(i).field);            
        }
        for(int i=0; i<scoreTree.successor.size(); i++)
        {
            printScoreTreeFields(scoreTree.successor.get(i), depth+1);
        }*/
        
        for(int i=0; i<scoreTree.successor.size(); i++)
        {
            System.out.println("Depth: " + depth + " pos: " + i);
            System.out.println("Score: " + scoreTree.successor.get(i).fieldScore + " Minimax: " + scoreTree.successor.get(i).minmaxValue);
            String cstring = "BLACK";
            if(scoreTree.successor.get(i).gameMoves[0].getStone().getColor() == COLOR_W)
                cstring = "WHITE";
            System.out.println("Color: " + cstring);
            System.out.println("");
            printScoreTreeFields(scoreTree.successor.get(i), depth+1);
        }
        
        cgui.update(scoreTree.field);
    }
    
    private ScoreTree generateScoreTree(ScoreTree scoreTree, boolean stoneColor, int depth, int maxDepth)
    {
        if(depth>maxDepth)
            return null; //getTopScoreTree(scoreTree);
        
        ArrayList<Stone> currentStones = new ArrayList();

        for(int y=0; y<8; y++)
        {
            for(int x=0; x<8; x++)
            {
                Stone s = scoreTree.field[y][x];
                
                if(s != null)
                {
                    if(s.getColor() == stoneColor)
                        currentStones.add(s);
                }
            }
        }
        
        ArrayList<ScoreTree> scoreTreeSuccessors = new ArrayList();
        
        for(int i=0; i<currentStones.size(); i++)
        {
            ArrayList<ScoreTree> tempScoreTreeList = generateScoreTreeNodesForStone(scoreTree.field, currentStones.get(i), stoneColor);
            
            for(int j=0; j<tempScoreTreeList.size(); j++)
                scoreTreeSuccessors.add(tempScoreTreeList.get(j));
        }
        
        scoreTree.successor = scoreTreeSuccessors;
        
        for(int i=0; i<scoreTree.successor.size(); i++)
        {
            //TODO: Replace score system by a more sophisticated one (a.k.a ask Tobi do to it)
            scoreTree.successor.get(i).fieldScore = generateScore(scoreTree.successor.get(i).field, stoneColor);
            
            scoreTree.successor.get(i).predecessor = scoreTree;
            
            generateScoreTree(scoreTree.successor.get(i), !stoneColor, depth+1, maxDepth);
        }
        
        return scoreTree;
    }
    
    /*
    function integer minimax(node, depth)
    if node is a terminal node or depth <= 0:
        return the heuristic value of node
    α = -∞
    for child in node:                       # evaluation is identical for both players 
        α = max(α, -minimax(child, depth-1))
    return α
    
    SOURCE: http://en.wikipedia.org/wiki/Minimax#Minimax_algorithm_with_alternate_moves
     */
    /*
    //TODO: Fix this, does not yet work correctly
    private int generateMiniMaxValue(ScoreTree scoreTree)
    {
        if(scoreTree.successor.isEmpty())
            return scoreTree.fieldScore;
        int alpha = -9999999;
        for(int i=0; i<scoreTree.successor.size(); i++)
        {
            alpha = Math.max(alpha, -generateMiniMaxValue(scoreTree.successor.get(i)));
            scoreTree.minmaxValue = alpha;
        }   
        return alpha;
    }*/
    
    private void generateMiniMaxValue(ScoreTree scoreTree)
    {
        getMinValue(scoreTree);
    }
    
    private int getMaxValue(ScoreTree scoreTree)
    {
        if(scoreTree.successor.isEmpty())
            return scoreTree.fieldScore;
        
        int alpha = -9999999;
        for(int i=0; i<scoreTree.successor.size(); i++)
        {
            alpha = Math.max(alpha, getMinValue(scoreTree.successor.get(i)));
        }
        
        scoreTree.minmaxValue = alpha;
        return alpha;
    }
    
    private int getMinValue(ScoreTree scoreTree)
    {
        if(scoreTree.successor.isEmpty())
            return scoreTree.fieldScore;
        
        int alpha = 9999999;
        for(int i=0; i<scoreTree.successor.size(); i++)
        {
             alpha = Math.min(alpha, getMaxValue(scoreTree.successor.get(i)));
        }
        
        scoreTree.minmaxValue = alpha;
        return alpha;
    }
    
    private ArrayList<ScoreTree> generateScoreTreeNodesForStone(Stone[][] field, Stone s, boolean stoneColor)
    {
        ArrayList<ScoreTree> scoreTreeList = new ArrayList();        
        
        int x = s.getPosX();
        int y = s.getPosY();
        
       if(isAllowedToMoveUp(s, stoneColor))
        {
            //TOP LEFT
            if((x>0) && (y>0))
            {
                if(field[y-1][x-1] == null)
                {
                    //TOP LEFT spot is free
                    ScoreTree scoreTree = new ScoreTree();
                    
                    scoreTree.field = cloneFiled(field);

                    ArrayList<GameMove> gameMoves = new ArrayList();
                    gameMoves.add(new GameMove(s, y-1, x-1));

                    Stone s_new = scoreTree.field[y][x];
                    scoreTree.field[y][x] = null;
                    scoreTree.field[y-1][x-1] = s_new;
                    s_new.setPosX(x-1);
                    s_new.setPosY(y-1); 

                    scoreTree.gameMoves = gameMoves.toArray(new GameMove[gameMoves.size()]);
                    
                    scoreTreeList.add(scoreTree);
                }
                else
                {
                    if((x>1) && (y>1))
                        if(field[y-1][x-1] != null)
                            if((field[y-1][x-1].getColor() != stoneColor) && (field[y-2][x-2] == null))
                            {
                                //TOP LEFT spot is occupied by enemy and the spot behind is free (We can kill him :)
                                ScoreTree scoreTree = new ScoreTree();                    
                                scoreTree.field = cloneFiled(field);
                                ArrayList<GameMove> gameMoves = generateListofAttackMoves(scoreTree.field, s, stoneColor, x, y);
                                scoreTree.gameMoves = gameMoves.toArray((new GameMove[gameMoves.size()]));
                                scoreTreeList.add(scoreTree);
                            }
                }
            }

            //TOP RIGHT
            if((x<7) && (y>0))
            {
                if(field[y-1][x+1] == null)
                {
                    //TOP RIGHT spot is free
                    ScoreTree scoreTree = new ScoreTree();
                    
                    scoreTree.field = cloneFiled(field);

                    ArrayList<GameMove> gameMoves = new ArrayList();
                    gameMoves.add(new GameMove(s, y-1, x+1));

                    Stone s_new = scoreTree.field[y][x];
                    scoreTree.field[y][x] = null;
                    scoreTree.field[y-1][x+1] = s_new;
                    s_new.setPosX(x+1);
                    s_new.setPosY(y-1); 

                    scoreTree.gameMoves = gameMoves.toArray((new GameMove[gameMoves.size()]));
                    
                    scoreTreeList.add(scoreTree);
                }
                else
                {
                    if((x<6) && (y>1))
                        if(field[y-1][x+1] != null)
                            if((field[y-1][x+1].getColor() != stoneColor) && (field[y-2][x+2] == null))
                            {
                                //TOP RIGHT spot is occupied by enemy and the spot behind is free (We can kill him :)
                                ScoreTree scoreTree = new ScoreTree();                    
                                scoreTree.field = cloneFiled(field);
                                ArrayList<GameMove> gameMoves = generateListofAttackMoves(scoreTree.field, s, stoneColor, x, y);
                                scoreTree.gameMoves = gameMoves.toArray((new GameMove[gameMoves.size()]));
                                scoreTreeList.add(scoreTree);
                            }
                }
            }
        }
        
        if(isAllowedToMoveDown(s, stoneColor))
        {
            //DOWN LEFT
            if((x>0) && (y<7))
            {
                if(field[y+1][x-1] == null)
                {
                    //DOWN LEFT spot is free
                    ScoreTree scoreTree = new ScoreTree();
                    
                    scoreTree.field = cloneFiled(field);

                    ArrayList<GameMove> gameMoves = new ArrayList();
                    gameMoves.add(new GameMove(s, y+1, x-1));

                    Stone s_new = scoreTree.field[y][x];
                    scoreTree.field[y][x] = null;
                    scoreTree.field[y+1][x-1] = s_new;
                    s_new.setPosX(x-1);
                    s_new.setPosY(y+1); 

                    scoreTree.gameMoves = gameMoves.toArray((new GameMove[gameMoves.size()]));
                    
                    scoreTreeList.add(scoreTree);
                }
                else
                {
                    if((x>1) && (y<6))
                        if(field[y+1][x-1] != null)
                            if((field[y+1][x-1].getColor() != stoneColor) && (field[y+2][x-2] == null))
                            {
                                //DOWN LEFT spot is occupied by enemy and the spot behind is free (We can kill him :)
                                
                                ScoreTree scoreTree = new ScoreTree();                    
                                scoreTree.field = cloneFiled(field);
                                
                                //System.out.println("---------DEBUG PRINT START-----------");
                                //cgui.update(scoreTree.field);
                                //System.out.println("---------DEBUG PRINT END-------------");
                                
                                ArrayList<GameMove> gameMoves = generateListofAttackMoves(scoreTree.field, s, stoneColor, x, y);
                                
                                //System.out.println("---------DEBUG PRINT START-----------");
                                //cgui.update(scoreTree.field);
                                //System.out.println("---------DEBUG PRINT END-------------");
                                
                                scoreTree.gameMoves = gameMoves.toArray((new GameMove[gameMoves.size()]));
                                scoreTreeList.add(scoreTree);
                            }
                }
            }
            
            //DOWN RIGHT
            if((x<7) && (y<7))
            {
                if(field[y+1][x+1] == null)
                {
                    //DOWN RIGHT spot is free
                    ScoreTree scoreTree = new ScoreTree();
                    
                    scoreTree.field = cloneFiled(field);

                    ArrayList<GameMove> gameMoves = new ArrayList();
                    gameMoves.add(new GameMove(s, y+1, x+1));

                    Stone s_new = scoreTree.field[y][x];
                    scoreTree.field[y][x] = null;
                    scoreTree.field[y+1][x+1] = s_new;
                    s_new.setPosX(x+1);
                    s_new.setPosY(y+1); 

                    scoreTree.gameMoves = gameMoves.toArray((new GameMove[gameMoves.size()]));
                    
                    scoreTreeList.add(scoreTree);
                }
                else
                {
                    if((x<6) && (y<6))
                        if(field[y+1][x+1] != null)
                            if((field[y+1][x+1].getColor() != stoneColor) && (field[y+2][x+2] == null))
                            {
                                //DOWN RIGHT spot is occupied by enemy and the spot behind is free (We can kill him :)
                                ScoreTree scoreTree = new ScoreTree();                    
                                scoreTree.field = cloneFiled(field);
                                ArrayList<GameMove> gameMoves = generateListofAttackMoves(scoreTree.field, s, stoneColor, x, y);
                                scoreTree.gameMoves = gameMoves.toArray((new GameMove[gameMoves.size()]));
                                scoreTreeList.add(scoreTree);
                            }
                }
            }
        }
        
        return scoreTreeList;
    }
    
    private Stone[][] cloneFiled(Stone[][] field)
    {
        Stone[][] RETfield = new Stone[8][8];
        
        for(int x=0; x<8; x++)
        {
            for(int y=0; y<8; y++)
            {
                if(field[y][x]!=null)
                    RETfield[y][x] = field[y][x].clone();
                else
                    RETfield[y][x] = null;
            }
        }
        
        return RETfield;
    }
    
    private ArrayList<GameMove> generateListofAttackMoves(Stone[][] field, Stone s, boolean stoneColor, int x, int y)
    {
        ArrayList<GameMove> gameMoves = new ArrayList();

        String dir = getStoneForcedMoveDirection(field, field[y][x], stoneColor);
        
        while(dir!=null)
        {
            if("topleft".equals(dir))
            {
                Stone s_new = field[y][x];
                field[y][x] = null;
                field[y-1][x-1] = null;
                field[y-2][x-2] = s_new;
                s_new.setPosX(x-2);
                s_new.setPosY(y-2);
                x=x-2;
                y=y-2;
                
                gameMoves.add(new GameMove(s, y-2, x-2));
            }
            
            if("topright".equals(dir))
            {
                Stone s_new = field[y][x];
                field[y][x] = null;
                field[y-1][x+1] = null;
                field[y-2][x+2] = s_new;
                s_new.setPosX(x+2);
                s_new.setPosY(y-2);
                x=x+2;
                y=y-2;
                
                gameMoves.add(new GameMove(s, y-2, x+2));
            }
            
            if("downleft".equals(dir))
            {
                Stone s_new = field[y][x];
                field[y][x] = null;
                field[y+1][x-1] = null;
                field[y+2][x-2] = s_new;
                s_new.setPosX(x-2);
                s_new.setPosY(y+2);
                x=x-2;
                y=y+2;
                
                gameMoves.add(new GameMove(s, y+2, x-2));
            }
            
            if("downright".equals(dir))
            {
                Stone s_new = field[y][x];
                field[y][x] = null;
                field[y+1][x+1] = null;
                field[y+2][x+2] = s_new;
                s_new.setPosX(x+2);
                s_new.setPosY(y+2);
                x=x+2;
                y=y+2;
                
                gameMoves.add(new GameMove(s, y+2, x+2));
            }
            
            dir = getStoneForcedMoveDirection(field, field[y][x], stoneColor);
        }
        
        return gameMoves;
    }
    
    private String getStoneForcedMoveDirection(Stone[][] field, Stone s, boolean stoneColor)
    {
        int x = s.getPosX();
        int y = s.getPosY();
        
        if(isAllowedToMoveUp(s, stoneColor))
        {
            //TOP LEFT
            if((x>1) && (y>1))
                if(field[y-1][x-1] != null)
                    if((field[y-1][x-1].getColor() != stoneColor) && (field[y-2][x-2] == null)) return "topleft";

            //TOP RIGHT
            if((x<6) && (y>1))
                if(field[y-1][x+1] != null)
                    if((field[y-1][x+1].getColor() != stoneColor) && (field[y-2][x+2] == null)) return "topright";
        }
        
        if(isAllowedToMoveDown(s, stoneColor))
        {
            //DOWN LEFT
            if((x>1) && (y<6))
                if(field[y+1][x-1] != null)
                    if((field[y+1][x-1].getColor() != stoneColor) && (field[y+2][x-2] == null)) return "downleft";
            
            //DOWN RIGHT
            if((x<6) && (y<6))
                if(field[y+1][x+1] != null)
                    if((field[y+1][x+1].getColor() != stoneColor) && (field[y+2][x+2] == null)) return "downright";
        }
        
        return null;
    }
    
    private boolean isAllowedToMoveUp(Stone s, boolean stoneColor)
    {
        if(s.IsDame() || (stoneColor==COLOR_B))
            return true;
        
        return false;
    }
    
    private boolean isAllowedToMoveDown(Stone s, boolean stoneColor)
    {
        if(s.IsDame()|| (stoneColor==COLOR_W))
            return true;
        
        return false;
    }
    
    private int generateScore(Stone[][] field, boolean stoneColor)
    {
        int numMyPieces = 0;
        int numEnemyPieces = 0;
        
        for (int x = 0; x < field.length; x++) 
        {
            for (int y = 0; y < field[x].length; y++) 
            {
                if (field[x][y] != null)
                {
                    if (field[x][y].getColor() == stoneColor) 
                    {
                        numMyPieces++;
                    }
                    else
                    {
                        numEnemyPieces++;
                    }
                }
            }
        }
        int score = numMyPieces - numEnemyPieces;
        if(score>=0)
            score+=2;
        else
            score-=2;
        return score;
    }
}
